package cn.com.cluster;

import cn.com.common.Invocation;
import cn.com.common.RegistryInfo;
import cn.com.common.URI;
import cn.com.registry.Notify;
import cn.com.rpc.invoke.Invoker;
import cn.com.rpc.invoke.RpcInvoker;
import lombok.Data;

import java.util.*;

/**
 * server dictionary
 *
 * @author jiaming
 */
@Data
public class ServiceDictionary<T> implements Notify {

    private volatile List<Invoker<T>> invokers;
    private volatile Map<String, Invoker<T>> invokerMap = new HashMap<>();
    private volatile boolean destory = false;

    @Override
    public synchronized void notify(List<? extends RegistryInfo> putRegInfos, List<? extends RegistryInfo> delRegInfos) {
        if ((putRegInfos == null || putRegInfos.isEmpty())
                && (delRegInfos == null || delRegInfos.isEmpty())) {
            return;
        }
        //invokerMap 结构key=appName+ip+port value=Invoker
        if (!delRegInfos.isEmpty()) {
            for (RegistryInfo delRegInfo : delRegInfos) {
                String serverKey = getKey(delRegInfo);
                if (invokerMap.containsKey(serverKey)) {
                    invokerMap.remove(serverKey);
                }
            }
        }
        if (!putRegInfos.isEmpty()) {
            for (RegistryInfo regInfo : putRegInfos) {
                String key = getKey(regInfo);
                URI uri = new URI();
                uri.setHost(regInfo.getHost());
                uri.setPort(regInfo.getPort());
                uri.setServiceName(regInfo.getAppName());
                RpcInvoker rpcInvoker = new RpcInvoker<T>(uri);
                invokerMap.put(key, rpcInvoker);
            }
        }
        List<Invoker<T>> newInvokerList = Collections.unmodifiableList(new ArrayList<>(invokerMap.values()));
        this.invokers = newInvokerList;
    }

    private String getKey(RegistryInfo delRegInfo) {
        return delRegInfo.getAppName() + "_" + delRegInfo.getHost() + "_" + delRegInfo.getPort();
    }

    public void destory() {
        if (destory) {
            return;
        }
        for (Invoker<T> invoker : invokers) {
            try {
                invoker.destory();
            } catch (Throwable e) {
            }
        }
    }

    public List<Invoker<T>> list(Invocation invocation) {
        return invokers;
    }

    public URI getUri() {
        return invokers.isEmpty() ? null : invokers.get(0).getUri();
    }
}
